import { createDefer, IPromiseDefer } from '../util';

export interface ITimer {
  defer: IPromiseDefer<any>;
  time: number;
  uid: number;
  started: boolean;
}

export class Timer {
  protected uid = 0;

  protected readonly timer = new Map<number, ITimer>();

  protected _sleep: ((time: number) => Promise<void>) | null;

  protected runJob = () => {
    if (this.timer.size) {
      // 触发立即执行
      Array.from(this.timer).forEach(([uid, iTask]) => {
        if (this._sleep && !iTask.started) {
          iTask.defer.resolve(this._sleep(iTask.time));
          iTask.started = true;
        }
      });
    }
  };

  public setSleepFn = (sleep: null | ((time: number) => Promise<void>)) => {
    this._sleep = sleep;
    this.runJob();
  };

  public wrapFn(uid: number, fn: Function, ...args: any): () => any {
    let timer = this.timer;
    return function () {
      if (timer.has(uid)) {
        try {
          const currentTask = timer.get(uid)!;
          currentTask.started = true;
          fn(...args);
        } finally {
          timer.delete(uid);
          timer = null!;
        }
      }
    };
  }

  public setTimeout = (fn: Function, time: number = 0, ...args: any[]) => {
    const val = ++this.uid;
    const defer = createDefer();
    defer.promise.then(this.wrapFn(val, fn, ...args));
    this.timer.set(val, {
      defer,
      uid: val,
      time,
      started: false,
    });
    this.runJob();
    return val;
  };

  public clearTimeout = (uid: any) => {
    if (typeof uid === 'number' && this.timer.has(uid)) {
      this.timer.delete(uid);
    }
  };

  public setInterval = () => {};

  public clearInterval = () => {};
}

export const globalTimer = new Timer();
